#!/usr/bin/env python
# -*- coding: utf-8 -*-
import getopt, os, time, sys, codecs, subprocess
import getpass
import ConfigParser
import imaplib
import email
import email.message
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders
from email.Header import decode_header

configfile='~/.imapstorage'
mailbox='FILESTORAGE'
detach_dir = '.'
defaultattachsize=10
cmd='list'
defaultkey='temp'
hostname='imap.gmail.com'
username='user'
password=''
section='default'
gmailhost='imap.gmail.com'
update=0

Usage = """Usage: %s [command] [-s <section> of cofig file ] [-u #update the selected file from server#] [files]

command can be one of list/upload/download/del.

need config file ~/.imapstorage
in which is:
[default]
hostname=<imap mail server>
username=<username>
password=<password>

[gmail]
hostname=imap.gmail.com
username=<username>
password=<password>
"""

def usage(reason=''):
	sys.stdout.flush()
	if reason: sys.stderr.write('\t%s\n\n' % reason)
	head, tail = os.path.split(sys.argv[0])
	sys.stderr.write(Usage % tail)
	sys.exit(1)

def args():
	global cmd
	global section
	global update
	if len(sys.argv) < 2:
			return []
	if sys.argv[1] in ('list', 'del', 'upload', 'download') :
		cmd=sys.argv[1]
		i=2
	else:
		i=1
	try:
		optlist, args = getopt.getopt(sys.argv[i:], 's:u',['section='])
	except getopt.GetoptError:
		usage()
	if cmd != 'list' and len(args) == 0:
		usage()
	
	for opt,arg in optlist:
		if opt in ('-s','--section'):
			section=arg
		elif opt in ('-u'):
			update=1
		else:
			usage()

	return args

def parser_config(section='default'):
	# Read the config file
	global hostname, username, password, attachsize, key
	config = ConfigParser.ConfigParser()
	config.read([os.path.expanduser(configfile)])
	try:
		hostname = config.get(section, 'hostname')
		username = config.get(section, 'username')
	except ConfigParser.NoOptionError or ConfigParser.NoSectionError:
		usage()
	try:
		password = config.get(section, 'password')
	except ConfigParser.NoOptionError:
		password = getpass.getpass('Password for '+username+': ')
	try:
		attachsize = int(config.get(section, 'attachsize'))
	except ConfigParser.NoOptionError:
		attachsize = defaultattachsize
	try:
		key = config.get(section, 'key')
	except ConfigParser.NoOptionError:
		key = defaultkey

def select_mailbox():
	try:
		typ, data = c.select(mailbox)
	except c.error:
		typ = 'NO'
	if typ == 'NO':
		c.create(mailbox)
		typ, data = c.select(mailbox)
#	print typ, data

def upload_file(path):
	if not os.access(path,os.R_OK):
		return -1

	bname=os.path.basename(path)
	if os.path.dirname(path):
		os.chdir(os.path.dirname(path))
	if os.access('.',os.W_OK):
		cache_dir='./'
	else:
		cache_dir=os.path.expanduser('~/')
	subprocess.Popen(['7zr', 'a', cache_dir+bname+'.7z',bname]).communicate()[0]
	fp=open(cache_dir+bname+'.7z',"rb")
	i=0
	buff = fp.read(attachsize*1024*1024)
#	filepart=[]
	date = formatdate(localtime=True)
	while ( len(buff) != 0 ):
		msg = MIMEMultipart()
		msg['From'] = str(i)+'@localhost'
		msg['To'] = str(i)+'@localhost'
		msg['Date'] = date
		msg['Subject'] = unicode( bname, "utf-8" )
		msg.attach( MIMEText('contents') )
		part = MIMEBase('application', "octet-stream")
		part.set_payload( buff )
		Encoders.encode_base64(part)
		part.add_header('Content-Disposition', 'attachment; filename="%s"' % bname+'__'+str(i)+'__')
		msg.attach(part)
		c.append(mailbox, '', imaplib.Time2Internaldate(time.time()), str(msg))
		buff = fp.read(attachsize*1024*1024)
		i=i+1

	fp.close()
	os.remove(cache_dir+bname+'.7z')

def download_file(name):
	#typ, msg_ids = c.search(None, '(SUBJECT "'+name+'")')
	msg_ids = list_file(name)
	if msg_ids == [ None ]:
		return 1
	sort=[None]*len(msg_ids[0].split())
	for num in msg_ids[0].split():
		typ, msg_data = c.fetch(num, '(BODY.PEEK[HEADER])')
		for response_part in msg_data:
			if isinstance(response_part, tuple):
				msg = email.message_from_string(response_part[1])
				sort[int(msg['to'].split('@')[0])]=num

	print sort
	att_path = os.path.join(detach_dir, name)
	print 'save to: '+att_path
	
	#Check if its already there
	if os.path.isfile(att_path) and update == 0:
		print "File",name,"already exist"
		ovwr=raw_input('Overwrite the file(Y/N): ')
		if ovwr in ('Y','y'):
			print 'overwriting...'
		else:
			print 'canceled'
			return 1
		# finally write the stuff
	fp = open(att_path+'.7z', 'wb')

	for num in sort:
		typ, data = c.fetch(num, '(RFC822)')
		email_body = data[0][1] # getting the mail content
		mail = email.message_from_string(email_body) # parsing the mail content to get a mail object
	
		#Check if any attachments at all
		if mail.get_content_maintype() != 'multipart':
			return
	
		print "["+mail["From"].split('@')[0]+"] ids: " + str(num)
	
		# we use walk to create a generator so we can iterate on the parts and forget about the recursive headache
		for part in mail.walk():
			# multipart are just containers, so we skip them
			if part.get_content_maintype() == 'multipart':
				continue
	
			# is this part an attachment ?
			if part.get('Content-Disposition') is None:
				continue
	
			fp.write(part.get_payload(decode=True))

	fp.close()
	subprocess.Popen(["rm", "-fr", att_path])
	if detach_dir:
		os.chdir(detach_dir)
	subprocess.Popen(['7zr', 'x', name+'.7z']).communicate()[0]
	os.remove(name+'.7z')

def list_file(subject=None):
	typ, data = c.search(None,'ALl')
	files={}
	if data == [None]:
		return [None]
	for num in data[0].split():
		typ, msg_data = c.fetch(num, '(BODY.PEEK[HEADER])')
		for response_part in msg_data:
			if isinstance(response_part, tuple):
				msg = email.message_from_string(response_part[1])
				msg_sub,enc=decode_header(msg['Subject'])[0]
				if enc:
					msg_sub = unicode(msg_sub , enc).encode('utf8','replace')
				if msg_sub in files:
					files[msg_sub]=files[msg_sub]+' '+str(num)
				else:
					files[msg_sub]=str(num)
	if subject == None:
		for ikey in files:
			print ikey,': ids:',files[ikey]
		return [files]
	elif subject in files:
		print subject,': ids:',files[subject]
		return [files[subject]]
	else:
		return [None]

def del_file(name):
	#typ, msg_ids = c.search(None, '(SUBJECT "'+name+'")')
	msg_ids = list_file(name)
	if msg_ids == [None]:
		return 1
	if hostname == gmailhost:
		for num in (msg_ids[0].split())[::-1]:
			print c.copy(num, '[Gmail]/Trash')
	else:
		for num in msg_ids[0].split():
			c.store(num, '+FLAGS', '\\Deleted')
		c.expunge()
	print 'file',name,'delected'

def unique_upload(name):
	#typ, old_msg_ids = c.search(None, '(SUBJECT "'+os.path.basename(name)+'")')
	del_file(os.path.basename(name))
	upload_file(name)
	print 'file uploaded'
	list_file(os.path.basename(name))

def open_connection(verbose=False):

	if verbose: print 'Connecting to', hostname
	connection = imaplib.IMAP4_SSL(hostname)

	if verbose: print 'Logging in as', username
	connection.login(username, password)
	return connection

if __name__ == '__main__':
	args=args()
	parser_config(section)
	c = open_connection(verbose=True)
	select_mailbox()
	if cmd == 'list':
		print "Available files are:"
		list_file()
	elif cmd == 'download':
		for file in args:
			if not os.path.basename(file):
				file=os.path.dirname(file)
			detach_dir=os.path.dirname(file).replace('file://','',1)
			download_file(os.path.basename(file))
	elif cmd == 'upload':
		for file in args:
			if not os.path.basename(file):
				file=os.path.dirname(file)
			unique_upload(file)
	elif cmd == 'del':
		for file in args:
			if not os.path.basename(file):
				file=os.path.dirname(file)
			del_file(os.path.basename(file))
	else:
		usage()

	c.close()
	c.logout()
